#include <gflags/gflags.h>
#include <pthread>
#include "spdlogger.hpp"
#include "etcd.hpp"
#include "channel.hpp"
#include "main.pb.h"

/*
   etcd服务注册与发现 & rpc远程调用联合调试
   1、服务端：定义一个echo服务，服务添加rpc服务器，注册echo服务
   2、客户端：定义一个服务信道管理对象，发现echo服务，rpc调用
*/

DEFINE_bool(mode, false, "日志输出模式，true:发布模式，false:调试模式");
DEFINE_int32(release_level, 0, "发布模式下日志记录等级，此等级以上日志都记录");
DEFINE_string(file, "file.txt", "发布模式下日志输出文件");

DEFINE_string(etcd_url, "http://127.0.0.1:2379", "客户端访问etcd服务的url");
DEFINE_string(server_base_dir, "/services", "服务根目录");
DEFINE_string(echo_server_name, "/echo", "实例名称");

int main(int argc, char *argv[])
{
    // 解析命令行参数
    google::ParseCommandLineFlags(&argc, &argv, true);

    // 初始化日志记录器
    ns_spdlogger::init_logger(FLAGS_mode, FLAGS_release_level, FLAGS_file);

    // 1、定义服务信道管理对象,并将其内部online和offline函数作为服务发现对象的回调
    std::shared_ptr<ns_channel::ServiceManager> service_manager = std::make_shared<ns_channel::ServiceManager>();
    service_manager->declare(FLAGS_server_base_dir + FLAGS_echo_server_name);
    auto cb_online = std::bind(&ns_channel::ServiceManager::online, service_manager.get(), std::placeholders::_1, std::placeholders::_2);
    auto cb_offline = std::bind(&ns_channel::ServiceManager::offline, service_manager.get(), std::placeholders::_1, std::placeholders::_2);

    // 2、服务发现对象（创建即监听）
    shared_ptr<ns_etcd::Discovery> dcy = make_shared<ns_etcd::Discovery>(
        FLAGS_etcd_url, FLAGS_server_base_dir, cb_online, cb_offline);

    while (1)
    {
        // 3、从信道管理对象中对应的服务中选择一个信道
        std::shared_ptr<brpc::Channel> channel = service_manager->choose(FLAGS_server_base_dir + FLAGS_echo_server_name);
        if (!channel)
        {
            // 选择失败，可能还没有该服务上线，或者服务上线没有提供服务的节点，一直循环等待
            std::this_thread::sleep_for(std::chrono::seconds(1));
            continue;
        }

        // 4、定义ns_brpc::EchoServer_Stub对象，进行rpc调用
        ns_brpc::EchoServer_Stub stub(channel.get());
        brpc::Controller *controller = new brpc::Controller();         // 上下文管理对象，判断rpc请求是否ok
        ns_brpc::EchoResponse *response = new ns_brpc::EchoResponse(); // 响应
        ns_brpc::EchoRequest request;                                  // 构建请求
        request.set_message("这是一个测试信息\n");
        stub.echo(controller, &request, response, nullptr); // 同步调用，不需要Closure
        if (controller->Failed() == true)
        {
            std::cout << "rpc调用失败\n";
        }
        else
        {
            std::cout << "[ECHO]:" << response->message() << std::endl;
        }
        delete controller;
        delete response;
        break;
    }
    return 0;
}